/*
 * $Id: SyncPackage.java 222 2008-03-27 04:27:49Z jasta $
 *
 * Copyright (C) 2008 Josh Guilfoyle <jasta@devtcg.org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 */

package org.devtcg.syncml.protocol;

import java.util.ArrayList;

import java.net.*;
import java.io.*;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.dom.DOMSource;

public class SyncPackage
{
	protected ArrayList<BaseCommand> mCommands =
	  new ArrayList<BaseCommand>(3);

	protected long mID;
	protected SyncSession mSession;
	protected long mNextCmdId = 1;

	protected int mMaxSize = 0;
	protected boolean mFinal = false;

	public SyncPackage(SyncSession session, String xml)
	  throws Exception
	{
		mSession = session;

		DocumentBuilderFactory parserFactory = 
		  DocumentBuilderFactory.newInstance();

		parserFactory.setFeature("http://xml.org/sax/features/validation", false);
		parserFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
		parserFactory.setValidating(false);

		DocumentBuilder p = parserFactory.newDocumentBuilder();

		Document doc = p.parse(new InputSource(new StringReader(xml)));

		Element root = doc.getDocumentElement();
		
		if (root.getNodeName().equals("SyncML") == false)
			throw new Exception("Whatever");

		NodeList hdr = root.getElementsByTagName("SyncHdr").item(0).getChildNodes();

		long id = -1;

		for (int i = 0; i < hdr.getLength(); i++)
		{
			Node n = hdr.item(i);

			if (n.getNodeName().equals("MsgID") == true)
				id = Long.valueOf(((Text)n.getFirstChild()).getNodeValue());
		}

		if (id == -1)
			throw new Exception("Ugh, no MessageID?");

		mID = id;

		NodeList body = root.getElementsByTagName("SyncBody").item(0).getChildNodes();

		for (int i = 0; i < body.getLength(); i++)
		{
			Node n = body.item(i);

			System.err.println("Node: " + n.getNodeName());

			if (n.getNodeName().equals("Final"))
				mFinal = true;
			else if (n.getNodeName().equals("Alert"))
				mCommands.add(new AlertCommand((Element)n));
			else if (n.getNodeName().equals("Status"))
				mCommands.add(new StatusCommand((Element)n));
			else if (n.getNodeName().equals("Sync"))
				mCommands.add(new SyncCommand((Element)n));
		}
	}

	public SyncPackage(SyncSession session, long id)
	{
		mSession = session;
		mID = id;
		mFinal = true;
	}

	public void setMaxMsgSize(int max)
	{
		mMaxSize = max;
	}

	public long getId()
	{
		return mID;
	}

	public boolean isFinal()
	{
		return mFinal;
	}

	public void setFinal(boolean f)
	{
		mFinal = f;
	}

	public void addCommand(BaseCommand cmd)
	{
		assert cmd.getId() == -1;
		cmd.setId(mNextCmdId++);
		mCommands.add(cmd);
	}

	public int getCommandLength()
	{
		return mCommands.size();
	}

	public BaseCommand getCommand(int n)
	{
		return mCommands.get(n);
	}

	public String toString()
	{
		StringBuilder b = new StringBuilder();

		b.append("<SyncML>\n");
		b.append("<SyncHdr>\n");
		b.append("<VerDTD>1.1</VerDTD>\n");
		b.append("<VerProto>SyncML/1.1</VerProto>\n");
		b.append("<SessionID>").append(mSession.getId()).append("</SessionID>\n");
		b.append("<MsgID>").append(mID).append("</MsgID>\n");
		b.append("<Target><LocURI>").append(mSession.getTargetURI()).append("</LocURI></Target>\n");
		b.append("<Source><LocURI>").append(mSession.getSourceURI()).append("</LocURI></Source>\n");

		if (mMaxSize > 0)
			b.append("<Meta><MaxMsgSize>").append(mMaxSize).append("</MaxMsgSize></Meta>\n");

		b.append("</SyncHdr>\n");
		b.append("<SyncBody>\n");

		assert mCommands.size() > 0;

		for (BaseCommand cmd: mCommands)
			b.append(cmd.toString());

		if (isFinal() == true)
			b.append("<Final></Final>\n");

		b.append("</SyncBody>\n");
		b.append("</SyncML>\n");

		return b.toString();
	}
}
